﻿using LandingPlan;
using Simulate;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Transactions;

namespace LandingPlan
{

    /// <summary>
    /// 项目信息变更工具数据层：提供项目信息变更的实际功能的实现
    /// </summary>
    internal class ProjectInfoChangedCmdFactory : ProjectInfoChangedCmd
    {
        /// <summary>
        /// 获取服务实例
        /// </summary>
        /// <returns></returns>
        private IProjectChange GetService()
        {
            return null;
        }

        /// <summary>
        /// 获取变更的项目信息集合
        /// </summary>
        /// <param name="filter">筛选条件</param>
        /// <returns></returns>
        internal PageList<ProjectChangedInfo> DataPortal_Execute_GetProjectInfoChangedList(ProjectInfoChangedParam filter)
        {
            var service = GetService();
            return service.GetProjectInfoChangedList(filter);
        }

        /// <summary>
        /// 变更项目信息
        /// </summary>
        /// <param name="projectChangedInfoList">为空时，表示全范围；不为空时，指定范围</param>
        internal void DataPortal_Execute_ChangeProjectInfo(List<ProjectChangedInfo> projectChangedInfoList)
        {
            if (projectChangedInfoList == null)
            {
                projectChangedInfoList = DataPortal_Execute_GetProjectInfoChangedList(new ProjectInfoChangedParam
                {
                    PageSize = -1
                })?.List;
            }
            projectChangedInfoList = projectChangedInfoList
                ?.Where(p => p != null)
                ?.ToList();
            if (projectChangedInfoList == null || projectChangedInfoList.Count == 0)
            {
                return;
            }

            var service = MPIMgr.GetService();

            var projCodeEmptyList = projectChangedInfoList.Where(p => string.IsNullOrEmpty(p.ProjCode)).ToList();
            if (projCodeEmptyList.Count != 0)
            {
                projCodeEmptyList.ForEach(changedInfo => service.OnProjectInfoChanged(new ProjectChangedResultItem
                {
                    SerialNo = changedInfo.SerialNo,
                    ProjCode = changedInfo.ProjCode,
                    ChangeStatus = ProjectInfoChangedStatusConst.C,
                    Message = "财务项目编号不能为空",
                }));
                projectChangedInfoList.RemoveAll(p => string.IsNullOrEmpty(p.ProjCode));
            }


            using (var ctx = new ContextManager<EFDataContext>())
            {
                foreach (var changedInfo in projectChangedInfoList)
                {
                    TransactionOptions opt = new TransactionOptions();
                    opt.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
                    opt.Timeout = TimeSpan.FromMinutes(10);
                    using (TransactionScope tr = new TransactionScope(TransactionScopeOption.RequiresNew, opt))
                    {
                        try
                        {
                            if (string.IsNullOrEmpty(changedInfo.ChangeType))
                            {
                                throw new Exception("变更类型为空！");
                            }

                            // 模拟获取项目信息
                            var projInfo = new PM_Project();

                            // 获取具体变更类型对应的变更服务实例
                            var metaService = MetaChangeBase.GetService(changedInfo.ChangeType);
                            if (metaService == null)
                            {
                                throw new Exception($"变更类型{changedInfo.ChangeType}不受支持！");
                            }

                            // 根据类型进行变更处理
                            metaService.Execute(ctx, tr, service, projInfo, changedInfo);
                        }
                        catch (Exception ex)
                        {
                            // 记录日志
                            var logContent = $"项目变更[{ProjectChangeTypeConst.GetName(changedInfo.ChangeType)}]时同步出错：{ex.Message}，堆栈：{ex.StackTrace}";

                        }
                    }
                }
            }
        }

        #region 项目信息变更具体实现

        /// <summary>
        /// 项目信息变更
        /// </summary>
        public abstract class MetaChangeBase
        {
            private static Dictionary<string, MetaChangeBase> MetaChangeServiceCache = null;
            private static object _lock = new object();
            /// <summary>
            /// 获取项目变更服务实例
            /// </summary>
            /// <param name="changeType"></param>
            /// <returns></returns>
            public static MetaChangeBase GetService(string changeType)
            {
                if (changeType == null)
                {
                    return null;
                }
                if (MetaChangeServiceCache != null && MetaChangeServiceCache.Count != 0)
                {
                    return !MetaChangeServiceCache.ContainsKey(changeType) ? null : MetaChangeServiceCache[changeType];
                }

                lock (_lock)
                {
                    if (MetaChangeServiceCache != null && MetaChangeServiceCache.Count != 0)
                    {
                        return !MetaChangeServiceCache.ContainsKey(changeType) ? null : MetaChangeServiceCache[changeType];
                    }
                    // 使用反射获取类型的所有成员类型（内部类型）

                    MetaChangeServiceCache = typeof(ProjectInfoChangedCmdFactory).GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic)
                        .Where(p => typeof(MetaChangeBase).IsAssignableFrom(p) && !p.IsAbstract)
                        .Select(p => (MetaChangeBase)Activator.CreateInstance(p))
                        .ToDictionary(p => p.ContrastType, p => p);
                }

                return !MetaChangeServiceCache.ContainsKey(changeType) ? null : MetaChangeServiceCache[changeType];
            }

            /// <summary>
            /// 执行变更
            /// </summary>
            /// <param name="ctx"></param>
            /// <param name="tr"></param>
            /// <param name="service"></param>
            /// <param name="projInfo"></param>
            /// <param name="changedInfo"></param>
            public void Execute(Simulate.ContextManager<Simulate.EFDataContext> ctx, TransactionScope tr, IProjectChange service, Simulate.PM_Project projInfo, ProjectChangedInfo changedInfo)
            {
                var result = new ProjectChangedResultItem()
                {
                    SerialNo = changedInfo.SerialNo,
                    ProjCode = changedInfo.ProjCode,
                };

                var validateResult = Validate(ctx, projInfo, changedInfo);
                result.Message = validateResult.Message;
                if (validateResult.ValidateCode == 0)
                {
                    Save(ctx, projInfo, changedInfo);
                    service.OnProjectInfoChanged(result);
                    tr.Complete();
                    return;
                }
                result.ChangeStatus = validateResult.ValidateCode == 1 ? ProjectInfoChangedStatusConst.B : ProjectInfoChangedStatusConst.C;
                result.Message = validateResult.Message;
                service.OnProjectInfoChanged(result);
                return;
            }

            /// <summary>
            /// 验证
            /// </summary>
            /// <param name="ctx"></param>
            /// <param name="projInfo"></param>
            /// <param name="changedInfo"></param>
            /// <returns></returns>
            private ValidateResult Validate(Simulate.ContextManager<Simulate.EFDataContext> ctx, Simulate.PM_Project projInfo, ProjectChangedInfo changedInfo)
            {
                var result = new ValidateResult();
                var newValue = GetInValue(changedInfo.NewContent);
                if (string.IsNullOrEmpty(newValue))
                {
                    result.ValidateCode = 2;
                    result.Message = $"{ProjectChangeTypeConst.GetName(this.ContrastType)}编号：[{changedInfo.NewContent}]在对照表中不存在，请检查对照表数据！";
                    return result;
                }
                return OnValidate(ctx, projInfo, changedInfo);
            }

            /// <summary>
            /// 变更类型
            /// </summary>
            public abstract string ContrastType
            {
                get;
            }

            /// <summary>
            /// 根据系统外部值获取系统对照内部值
            /// </summary>
            /// <param name="outValue"></param>
            /// <returns></returns>
            protected string GetInValue(string outValue)
            {
                // 模拟从对照表获取系统值
                return Simulate.MPIMgr.GetContrastValue(this.ContrastType, outValue);
            }

            /// <summary>
            /// 验证
            /// </summary>
            /// <param name="ctx"></param>
            /// <param name="projInfo"></param>
            /// <param name="changedInfo"></param>
            /// <returns></returns>
            protected abstract ValidateResult OnValidate(Simulate.ContextManager<Simulate.EFDataContext> ctx, Simulate.PM_Project projInfo, ProjectChangedInfo changedInfo);

            /// <summary>
            /// 保存
            /// </summary>
            /// <param name="ctx"></param>
            /// <param name="projInfo"></param>
            /// <param name="changedInfo"></param>
            protected abstract void Save(Simulate.ContextManager<Simulate.EFDataContext> ctx, Simulate.PM_Project projInfo, ProjectChangedInfo changedInfo);

            /// <summary>
            /// 记录变更日志
            /// </summary>
            /// <param name="projInfo"></param>
            /// <param name="changedInfo"></param>
            /// <param name="newValue"></param>
            protected abstract void Log(PM_Project projInfo, ProjectChangedInfo changedInfo, string newValue);

            /// <summary>
            /// 校验结果
            /// </summary>
            protected class ValidateResult
            {
                /// <summary>
                /// 校验结果编码
                ///     0：继续执行
                ///     1：数据一致，无需执行
                ///     2：执行失败
                /// </summary>
                public int ValidateCode { get; set; }

                public string Message { get; set; }
            }
        }

        /// <summary>
        /// 人员信息变更
        /// </summary>
        public class MetaChange_LPerson : MetaChangeBase
        {
            public override string ContrastType => ProjectChangeTypeConst.LPersonId;
            protected override void Save(Simulate.ContextManager<Simulate.EFDataContext> ctx, Simulate.PM_Project projInfo, ProjectChangedInfo changedInfo)
            {
                // 模拟更新执行
                //ctx.DataContext.UpdateByPK<PM_Project>(p => new PM_Project
                //{
                //    LPersonId = person.PersonId,
                //    ChangedDate = DateTime.Now,
                //    ChangedUser = EF.Basic.UserContext.UserID
                //}, sycnItem.ProjCode);
            }

            protected override ValidateResult OnValidate(Simulate.ContextManager<Simulate.EFDataContext> ctx, Simulate.PM_Project projInfo, ProjectChangedInfo changedInfo)
            {
                var newValue = GetInValue(changedInfo.NewContent);
                if (projInfo.LPersonId == newValue)
                {
                    return new ValidateResult
                    {
                        ValidateCode = 1,
                        Message = $"财务系统{ProjectChangeTypeConst.GetName(this.ContrastType)}变更前后一致，无需操作！"
                    };
                }
                // 校验人员是否不存在

                // 返回结果
                return new ValidateResult
                {
                    ValidateCode = 0,
                };
            }

            protected override void Log(PM_Project projInfo, ProjectChangedInfo changedInfo, string newValue)
            {
                // 模拟记录 变更记录
            }
        }

        #endregion
    }


}

namespace Simulate
{

    /// <summary>
    /// 数据上下文模拟管理类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ContextManager<T> : IDisposable
    {
        public void Dispose()
        {
            throw new NotImplementedException();
        }
    }


    /// <summary>
    /// 数据上下文模拟类
    /// </summary>
    public class EFDataContext
    {

    }

    /// <summary>
    /// 项目表数据模拟类
    /// </summary>
    public class PM_Project
    {
        public string LPersonId { get; set; }
    }

    public class MPIMgr
    {
        public static IProjectChange GetService()
        {
            return null;
        }
        public static string GetContrastValue(string contrastType, string outValue)
        {
            return new Random().Next(0, 10) > 5 ? null : $"NewValue{outValue}";
        }
    }
}
